package asia.yuanding.wechat.web.netty.handler;

import asia.yuanding.wechat.web.entity.User;
import asia.yuanding.wechat.web.netty.manager.ChannelManager;
import asia.yuanding.wechat.web.service.UserService;
import cn.hutool.json.JSONObject;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;

@Slf4j
@Component
@ChannelHandler.Sharable
public class WebSocketFrameHandler extends SimpleChannelInboundHandler<WebSocketFrame> {

    @Autowired
    private MessageDispatcher messageDispatcher;

    @Resource
    private UserService userService;


    public WebSocketFrameHandler() {
        super();
    }


    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        // 保存一下用户最后上线时间

        if (ctx.channel().attr(AttributeKey.valueOf("uId")).get() != null) {
            String uId = ctx.channel().attr(AttributeKey.valueOf("uId")).get().toString();

            userService.lambdaUpdate().eq(User::getUid, uId)
                    .set(User::getLastTime, new Date())
                    .update();

            log.info("{}:断开连接" , uId);
        }

    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {

        log.info("注册了:{}" , ctx.channel().id());
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            switch (event.state()) {
                case READER_IDLE: // 读超时，客户端可能断开
                    System.out.println("读超时，关闭连接：" + ctx.channel().id());
                    ChannelManager.removeUser(ctx.channel().attr(AttributeKey.valueOf("uId")).get().toString());
                    ctx.close();
                    break;
                case WRITER_IDLE: // 写超时，发送心跳包给客户端
                    ctx.writeAndFlush(new TextWebSocketFrame("{\"type\":\"ping\"}"));
                    break;
                default:
                    break;
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) {
        if (frame instanceof TextWebSocketFrame) {
            // 接收到文本消息
            String request = ((TextWebSocketFrame) frame).text();
            log.info("收到消息：{}", request);

            JSONObject reqEntity = new JSONObject(request);
            String type = reqEntity.getStr("type");
            String method = reqEntity.getStr("method");

            if (type == null || method == null) {
                ctx.writeAndFlush(new TextWebSocketFrame("{\"error\":\"缺少type或method参数\"}"));
                return;
            }

            // 构建消息类型：type.method
            String messageType = type + "." + method;
            
            try {
                // 使用新的消息调度器处理消息
                Object result = messageDispatcher.dispatch(messageType, reqEntity, ctx);
                
                if (result != null) {
                    // 如果有返回结果，发送给客户端
                    if (result instanceof String) {
                        ctx.writeAndFlush(new TextWebSocketFrame((String) result));
                    } else {
                        ctx.writeAndFlush(new TextWebSocketFrame(new JSONObject(result).toString()));
                    }
                }
            } catch (Exception e) {
                log.error("处理消息失败: type={}, method={}, error={}", type, method, e.getMessage(), e);
                ctx.writeAndFlush(new TextWebSocketFrame("{\"error\":\"消息处理失败\"}"));
            }
            
        } else if (frame instanceof CloseWebSocketFrame) {
            ctx.channel().close();
        } else if (frame instanceof PingWebSocketFrame) {
            ctx.channel().writeAndFlush(new PongWebSocketFrame(frame.content().retain()));
        } else {
            throw new UnsupportedOperationException("不支持的帧类型: " + frame.getClass().getName());
        }
    }
}
